﻿using LeRenard.Libraries.Drawing.GdiPlus.Forms;
using LeRenard.ScriptWars.Model.Entities;
using LeRenard.ScriptWars.Model.GridSystem;
using LeRenard.ScriptWars.Model.Scripting;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Windows.Forms;

namespace LeRenard.ScriptWars.Model.UI.WinForms.GdiPlus
{
    public class Main : GdiPlusForm
    {
        /// <summary>
        /// Holds a reference to the game.
        /// </summary>
        private readonly Game _game;

        /// <summary>
        /// Holds date and time the last turn occured.
        /// </summary>
        private DateTime? _lastTurn;

        public Main()
            : base(new Size(750, 750))
        {
            this.StartPosition = FormStartPosition.CenterScreen;
            this.MaximizeBox = false;

            this.ShowFps = true;
            this.ShowConsole = true;

            // Prepare scripts
            var scripts = new List<IScript>();
            var wandererScriptFile = new FileInfo("Content/Scripts/Wanderer.txt");
            var wandererScript = Script.FromFile(wandererScriptFile);            
            scripts.Add(wandererScript);
            /*var linearWalkerScriptFile = new FileInfo("Content/Scripts/LinearWalker.txt");
            var linearWalkerScript = Script.FromFile(linearWalkerScriptFile);            
            scripts.Add(linearWalkerScript);*/
            var squarerScriptFile = new FileInfo("Content/Scripts/Squarer.txt");
            var squarerScript = Script.FromFile(squarerScriptFile);
            scripts.Add(squarerScript);

            // Create game
            _game = new Game(scripts, new GridSize(10, 10));
        }

        public override void Draw(IBuffer buffer)
        {
            DrawGrid(buffer);
            DrawEntities(buffer);

            if (_lastTurn == null) {
                _lastTurn = DateTime.Now;
            } else {
                var timeDifference = DateTime.Now.Subtract(_lastTurn.Value);
                if (timeDifference.TotalMilliseconds > 80) {
                    _lastTurn = DateTime.Now;
                    _game.Next();
                    LogToConsole("Making turn #{0}".FormatWith(_game.Turns));
                }
            }
        }

        private void DrawGrid(IBuffer buffer)
        {
            var backgroundBrush = new SolidBrush(Color.FromArgb(150, 20, 20, 20));
            buffer.Graphics.FillRectangle(backgroundBrush, new Rectangle() { X = 0, Y = 0, Size = buffer.Size });

            var blockSize = CalculateBlockSize(buffer.Size, _game.Grid.Size);

            for (int y = 0; y < _game.Grid.Size.Height; y++) {
                for ( int x = 0; x < _game.Grid.Size.Width; x++){

                    var rectangle = new RectangleF() {
                        Size = blockSize,
                        X = (blockSize.Width * x) + 16 + (x * 1),
                        Y = (blockSize.Height * y) + 16 + (y * 1)
                    };                    

                    var blockBrush = new SolidBrush(Color.FromArgb(255, 35, 35, 35));
                    buffer.Graphics.FillRectangle(blockBrush, rectangle);                    
                }
            }
        }

        private void DrawEntities(IBuffer buffer)
        {
            var blockSize = CalculateBlockSize(buffer.Size, _game.Grid.Size);

            for (int y = 0; y < _game.Grid.Size.Height; y++) {
                for (int x = 0; x < _game.Grid.Size.Width; x++) {

                    var entity = _game.Grid.Layout[y,x].Value;
                    if(entity != null) {

                        var alpha = 35;
                        var color = Color.FromArgb(alpha, entity.Script.Color);

                        var entityBrush = new SolidBrush(color);
                        for (int i = 0; i < 2; i++) {
                            var rectangle = new RectangleF() {
                                Width = blockSize.Width - (2*i),
                                Height = blockSize.Height - (2*i),
                                X = ((blockSize.Width) * x) + 16 + (x * 1) + (1*i),
                                Y = ((blockSize.Height) * y) + 16 + (y * 1) + (1*i)
                            };                            
                            buffer.Graphics.FillRectangle(entityBrush, rectangle);
                        }

                        this.DrawString(buffer, entity.Script.Name, ((blockSize.Width) * x) + 16 + (x * 1), ((blockSize.Width) * y) + 16 + (y * 1), brush: new SolidBrush(Color.FromArgb(180, color)));

                        var directionSize = new SizeF(blockSize.Width / 8, blockSize.Height / 8);
                        var dWidth = 0f;
                        var dHeight = 0f;
                        switch(entity.Direction){                                                
                            case Direction.North:
                                dWidth = blockSize.Width/2 - directionSize.Width/2;
                                dHeight += 4;
                                break;
                            case Direction.East:
                                dWidth = blockSize.Width - directionSize.Width;
                                dHeight = blockSize.Height/2 - directionSize.Height/2;
                                dWidth -= 4;
                                break;
                            case Direction.South:
                                dWidth = blockSize.Width / 2 - directionSize.Width / 2;
                                dHeight = blockSize.Height - directionSize.Height;
                                dHeight -= 4;
                                break;
                            case Direction.West:
                                dHeight = blockSize.Height/2 - directionSize.Height/2;
                                dWidth += 4;
                                break;                            
                            default:
                                break;
                        }                        
                        var directionRectangle = new RectangleF() {
                            Size = directionSize,
                            X = ((blockSize.Width) * x) + 16 + (x * 1) + dWidth,
                            Y = ((blockSize.Height) * y) + 16 + (y * 1) + dHeight
                        };
                        buffer.Graphics.FillEllipse(new SolidBrush(Color.FromArgb(255, Color.AntiqueWhite)), directionRectangle);

                        directionRectangle = new RectangleF() {
                            Size = directionSize,
                            X = ((blockSize.Width) * x) + 16 + (x * 1) + dWidth,
                            Y = ((blockSize.Height) * y) + 16 + (y * 1) + dHeight
                        };
                        if (entity.Direction == Direction.North) {
                            directionRectangle.Y += 4;
                            directionRectangle.Height += 4;
                        }
                        if (entity.Direction == Direction.East) {
                            directionRectangle.X -= 8;
                            directionRectangle.Width += 2;
                        }
                        if (entity.Direction == Direction.South) {
                            directionRectangle.Y -= 8;
                            directionRectangle.Height += 2;
                        }
                        if (entity.Direction == Direction.West) {
                            directionRectangle.X += 4;
                            directionRectangle.Width += 4;
                        }
                        buffer.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(255, Color.AntiqueWhite)), directionRectangle);                        
                    }
                }
            }
        }

        private SizeF CalculateBlockSize(Size bufferSize, GridSize gridSize)
        {
            var sideBuffer = 16 * 2;
            var insideBuffer = 1;

            var xAmount = gridSize.Width;
            var yAmount = gridSize.Height;

            var totalBufferX = sideBuffer + (xAmount * insideBuffer);
            var totalBufferY = sideBuffer + (yAmount * insideBuffer);

            float blockSizeX = ((float)bufferSize.Width / (float)xAmount) - 4.0f/*- totalBufferX*/;
            float blockSizeY = ((float) bufferSize.Height / (float)yAmount) - 4.0f/*- totalBufferY*/;

            return new SizeF(blockSizeX, blockSizeY);
        }
    }
}
